package cc.rengu.redp.system.utils;

import cc.rengu.redp.common.utils.SpringContextUtil;
import cc.rengu.redp.system.domain.HolidayInfo;
import cc.rengu.redp.system.domain.Holidays;
import cc.rengu.redp.system.service.CommonHolidaysService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;

/**
 * 节假日计算的公共方法
 *
 * @author xushitang
 */
@Slf4j
public class BizDateUtil {

    private static CommonHolidaysService commonHolidaysService = SpringContextUtil.getBean(CommonHolidaysService.class);

    private BizDateUtil(){}

    /**
     * 判断两个日期之间相差多少个工作日
     *
     * @param dateStart 起始日期（yyyyMMdd）
     * @param dateEnd   结束日期（yyyyMMdd）
     * @return
     */
    public static int diffWeekDays(String dateStart, String dateEnd) {
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyyMMdd");
        LocalDate ldStart = LocalDate.parse(dateStart, dtf);
        LocalDate ldEnd = LocalDate.parse(dateEnd, dtf);

        //起始日期必须小于结束日期
        if (ldStart.isAfter(ldEnd)){
            return -1;
        }

        //完整的周数
        int fullWeekNum = (int) ((ldEnd.toEpochDay() - ldStart.toEpochDay() + 1) / 7);
        int fullWeekNumRemainder = (int) ((ldEnd.toEpochDay() - ldStart.toEpochDay() + 1) % 7);
        int workDaysAtStart = 0;
        int workDaysAtEnd = 0;

        //余数不为零时考虑起始周和结束周，至少有一个周是不完整的
        if (fullWeekNumRemainder != 0) {
            //起始不完整周数工作日计算
            int dayOfWeekAtStart = ldStart.getDayOfWeek().getValue();
            //等于6、7时该周没有工作日，等于1时属于完整周
            if (dayOfWeekAtStart != 6 && dayOfWeekAtStart != 7 && dayOfWeekAtStart != 1) {
                workDaysAtStart = 5 - dayOfWeekAtStart + 1;
            }

            //结束不完整周数工作日计算
            int dayOfWeekAtEnd = ldEnd.getDayOfWeek().getValue();
            //不考虑等于7，等于7是完整周
            if (dayOfWeekAtEnd == 6) {
                workDaysAtEnd = 5;
            } else if (dayOfWeekAtEnd < 6) {
                workDaysAtEnd = dayOfWeekAtEnd;
            }

            if (dayOfWeekAtEnd >= dayOfWeekAtStart) {
                fullWeekNum--;
            }
        }

        int adjToHoliday = commonHolidaysService.count(new LambdaQueryWrapper<HolidayInfo>()
                .between(HolidayInfo::getBatchDate, dateStart, dateEnd)
                .eq(HolidayInfo::getHolidayFlag, "Y"));

        int adjToWorkday = commonHolidaysService.count(new LambdaQueryWrapper<HolidayInfo>()
                .between(HolidayInfo::getBatchDate, dateStart, dateEnd)
                .eq(HolidayInfo::getHolidayFlag, "N"));

        return fullWeekNum * 5 + workDaysAtStart + workDaysAtEnd + adjToWorkday - adjToHoliday;
    }

    /**
     * 工作日计算
     * @param date
     * @param workdays 工作日 （正向表示相加，负向表示相减）
     * @return
     */
    public static String addWorkDays(String date, int workdays) {
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyyMMdd");
        LocalDate ldInit = LocalDate.parse(date, dtf);
        int absWorkdays = Math.abs(workdays);
        LocalDate ldResult = ldInit;
        while (absWorkdays != 0) {
            ldResult = workdays > 0 ? ldResult.plusDays(1) : ldResult.minusDays(1);
            while (commonHolidaysService.isHoliday(ldResult)) {
                ldResult = workdays > 0 ? ldResult.plusDays(1) : ldResult.minusDays(1);
            }
            absWorkdays--;
        }
        return ldResult.format(dtf);
    }

    /**
     * 判断一个日期是否节假日
     *
     * @param dateStr 日期（yyyyMMdd）
     * @return boolean
     **/
    public static boolean isHoliday(String dateStr) {
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyyMMdd");
        LocalDate ld = LocalDate.parse(dateStr, dtf);
        return commonHolidaysService.isHoliday(ld);
    }
}